#ifndef AFCORE_DATABASE_DATABASE_DATABASE_PREPAREDSTATEMENT_MYSQL_
#define AFCORE_DATABASE_DATABASE_DATABASE_PREPAREDSTATEMENT_MYSQL_

#include <string>
#include <vector>

#include "define.h"
#include "database_fwd.h"
#include "database_mysql_head.h"
#include "nocopyable.h"

namespace afcore {

/// @brief  数据库
namespace database {

class CMysqlConnection;

/// @brief  准备状态 mysql
class AFCORE_DATABASE_API CPreparedStatementMysql
  : public CNocopyable {
  friend class CPreparedStatementBase;
  friend class CMysqlConnection;
public:
  /// @brief  构造函数
  /// @param  stmt            准备状态
  /// @param  query_string    查询语句
  CPreparedStatementMysql(SMysqlStmt* stmt, std::string query_string);
  /// @brief  析构函数
  ~CPreparedStatementMysql();

  /// @brief  设置空值
  /// @param  index           参数绑定位置
  void SetNull(const uint8_t index);
  /// @brief  设置 bool 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 bool 类型值
  void SetBool(const uint8_t index, const bool value);
  /// @brief  设置 uint8_t 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 uint8_t 类型值
  void SetUInt8(const uint8_t index, const uint8_t value);
  /// @brief  设置 uint16_t 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 uint16_t 类型值
  void SetUInt16(const uint8_t index, const uint16_t value);
  /// @brief  设置 uint32_t 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 uint32_t 类型值
  void SetUInt32(const uint8_t index, const uint32_t value);
  /// @brief  设置 uint64_t 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 uint64_t 类型值
  void SetUInt64(const uint8_t index, const uint64_t value);
  /// @brief  设置 int8_t 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 int8_t 类型值
  void SetInt8(const uint8_t index, const int8_t value);
  /// @brief  设置 int16_t 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 int16_t 类型值
  void SetInt16(const uint8_t index, const int16_t value);
  /// @brief  设置 int32_t 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 int32_t 类型值
  void SetInt32(const uint8_t index, const int32_t value);
  /// @brief  设置 int64_t 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 int64_t 类型值
  void SetInt64(const uint8_t index, const int64_t value);
  /// @brief  设置 float 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 float 类型值
  void SetFloat(const uint8_t index, const float value);
  /// @brief  设置 double 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 double 类型值
  void SetDouble(const uint8_t index, const double value);
  /// @brief  设置 字节流 类型值
  /// @param  index           参数绑定位置
  /// @param  value           要设置的 字节流 类型值
  /// @param  is_string       是否为字符串 verchar
  void SetBinary(const uint8_t index, const std::vector<uint8_t>& value, bool is_string);

  /// @brief  获取参数数量
  /// @return 参数数量
  uint32_t GetParameterCount() const { return param_count_; }

protected:
  /// @brief  获取mysql准备状态
  /// @return mysql准备状态
  SMysqlStmt* GetStmt() { return stmt_mysql_; }
  /// @brief  获取mysql绑定参数
  /// @return mysql绑定参数
  SMysqlBind* GetBind() { return bind_; }
  /// @brief  清理参数
  void ClearParameters();
  /// @brief  断言参数位置
  /// @param  index       要断言的参数位置
  void AssertValidIndex(uint8_t index);
  /// @brief  获取mysql查询语句字符串
  /// @return mysql查询语句字符串
  /// @note   将准备语句中的?替换掉
  std::string GetQueryString() const;
protected:
  CPreparedStatementBase* stmt_ {nullptr};  ///< 系统内用 准备状态
private:
  SMysqlStmt* stmt_mysql_ {nullptr};        ///< mysql 准备状态
  uint32_t param_count_ {0};                ///< 参数数量
  std::vector<bool> params_set_;            ///< 参数位图
  SMysqlBind* bind_ {nullptr};              ///< mysql 绑定参数
  const std::string query_string_;          ///< 查询语句
};

} // !namespace database

} // !namespace afcore

#endif //! AFCORE_DATABASE_DATABASE_DATABASE_PREPAREDSTATEMENT_MYSQL_